package hapi.util;

class DynamicProxy<T> implements Dynamic {
	
	public var before:List<String -> Array<Dynamic> -> Void>;
	public var after:List<String -> Dynamic -> Void>;
	var inst:T;
	
	public function new(inst, interfaceToIntercep:Class<T>){
		this.inst = inst;
		before = new List();
		after = new List();
		
		for(fname in Type.getInstanceFields(interfaceToIntercep)){
			var field = Reflect.field(inst, fname);
			if(Reflect.isFunction(field))
				Reflect.setField(this, fname, methodInterceptor(field, fname));
		}
	}
	
	public static function create<T>(inst:T, interfaceToIntercep:Class<T>, ?before, ?after):T {
		var proxy = new DynamicProxy(inst, interfaceToIntercep);
		if( before != null ) proxy.before = before;
		if( after != null ) proxy.after = after;
		return cast proxy;
	}
	
	function methodInterceptor(method:Dynamic, methodName:String) {
		var self = this;
		var f = function(args) {
			for ( f in self.before ) f(methodName, args);
			var r = Reflect.callMethod(self.inst, method, args);
			for ( f in self.after ) f(methodName, r);
			return r;
		}
		return Reflect.makeVarArgs(f);
	}
	
	public function toString() {
		return "DynamicProxy<"+Type.getClassName(Type.getClass(this.inst))+">";
	}
}